#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kmod.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/uaccess.h>



struct sr04_struct{
    int echo_irq;
    struct gpio_desc *trig;     /* gpio描述符 */
    struct gpio_desc *echo;     /* gpio描述符 */
};

static struct sr04_struct *sensor_sr04;

/* 1-确定主设备号                                                                 */
static int major = 0;
static u64 pre_count_ns = 0;
static u64 count_ns = 0;    /* 记录echo高电平时间 */
static struct class *sr04_class;


static DECLARE_WAIT_QUEUE_HEAD(sr04_waitqueue);

static int sensor_sr04_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    int len;
    
    len = (size < 4) ? 4 : size;

    gpiod_set_value(sensor_sr04->trig, 1);
    udelay(15); // 延时15us
    gpiod_set_value(sensor_sr04->trig, 0);
    
    wait_event_interruptible(sr04_waitqueue, count_ns);  // 等待事件条件为真
    copy_to_user(buf, &count_ns, len);
    count_ns = 0;

    return len;
}


/* 按键读取驱动 file_operations */
static struct file_operations xxh_sr04_drv = {
    .owner = THIS_MODULE,
    .read  = sensor_sr04_drv_read,
};

/* 中断服务函数 */
static irqreturn_t xxh_sensor_sr04_isr(int irq, void *dev_id)
{
    struct sr04_struct *sr04 = dev_id;

    //printk("%s line %s: sr04_struct ptr = 0x%p\n", __FUNCTION__, __LINE__, sr04);
    if(pre_count_ns == 0)
    {
        /* 上升沿，开始计时 */
        pre_count_ns = ktime_get_ns();
    }
    else
    {
        count_ns = ktime_get_ns() - pre_count_ns;
        pre_count_ns = 0;
        wake_up(&sr04_waitqueue);
    }

    return IRQ_HANDLED;
}


/*
 * 4、从platform device获取GPIO
 *    把file_operations结构体告诉内核：注册驱动程序
 */
static int xxh_sensor_sr04_probe(struct platform_device *pdev)
{
    int err, index;
    int count;


    sensor_sr04 = kzalloc(sizeof(struct sr04_struct), GFP_KERNEL);
    if(sensor_sr04 == NULL)
        return -1;

    /* 设备节点获取 */
    sensor_sr04->trig = gpiod_get(&pdev->dev, "trig", GPIOD_OUT_LOW);
    sensor_sr04->echo = gpiod_get(&pdev->dev, "echo", GPIOD_IN);


    /* 获取GPIO中断号 */
    sensor_sr04->echo_irq = gpiod_to_irq(sensor_sr04->echo);
    if (sensor_sr04->echo_irq < 0) {
        err = sensor_sr04->echo_irq;
        dev_err(&pdev->dev,
            "Unable to get irq number for GPIO %d, error %d\n",
            desc_to_gpio(sensor_sr04->echo), err);
        return err;
    }
    else {
        printk("%s %s line %d: get echo irq number is %d\n", __FILE__, __FUNCTION__, __LINE__, sensor_sr04->echo_irq);
    }
    /* 申请中断 */
    err = request_irq(sensor_sr04->echo_irq, xxh_sensor_sr04_isr, 
                      IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, 
                      "xxh_sensor_sr04", &sensor_sr04);

    /* 注册file_operations结构体 */
    major = register_chrdev(0, "xxh_sr04", &xxh_sr04_drv);
    sr04_class = class_create(THIS_MODULE, "xxhsr04");  /* /sys/class/xxhkey */
    err = PTR_ERR(sr04_class);
    if (IS_ERR(sr04_class)) {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
        unregister_chrdev(major, "xxh_sr04");
        return -1;
    }

    device_create(sr04_class, NULL, MKDEV(major, 0), NULL, "xxhsr04"); /* /dev/xxhkey */
    
    return 0;
}

static int xxh_sensor_sr04_remove(struct platform_device *dev)
{
    struct device_node *np;
    int index, count;
    int ret;
    
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    device_destroy(sr04_class, MKDEV(major, 0));
    class_destroy(sr04_class);
    unregister_chrdev(major, "xxh_sr04");

    /* 设备节点释放 */
    free_irq(sensor_sr04->echo_irq, &sensor_sr04);
    gpiod_put(sensor_sr04->trig);
    gpiod_put(sensor_sr04->echo);

    kfree(sensor_sr04);
    
    return 0;
}


static const struct of_device_id sensor_sr04_dev[] = {
    {.compatible = "xxh,sensor_sr04"},
    {},
};

/* 1、定义platform_drver结构体 */
static struct platform_driver xxh_sensor_sr04_driver = {
    .probe  = xxh_sensor_sr04_probe,
    .remove = xxh_sensor_sr04_remove,
    .driver = {
        .name   = "xxh_sensor_sr04",
        .of_match_table = sensor_sr04_dev,
    },
};


static int __init sensor_sr04_init(void)
{
    int err;
    printk("%s line %d\n", __FUNCTION__, __LINE__);
    err = platform_driver_register(&xxh_sensor_sr04_driver);

    return err;
}


static void __exit sensor_sr04_exit(void)
{
    printk("%s line %d\n", __FUNCTION__, __LINE__);
    platform_driver_unregister(&xxh_sensor_sr04_driver);
    return;
}

/* 7. 其他完善：提供设备信息，自动创建设备节点                                     */

module_init(sensor_sr04_init);
module_exit(sensor_sr04_exit);

MODULE_AUTHOR("xxh <1293793140@qq.com>");
MODULE_LICENSE("GPL");

